package com.cynen.util;

import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.UUID;

@Component
public class HttpUtils {

    /**
     * 指定存储的路径.
     */
    @Value("${pic.save.path}")
    private String desPath;
    // 创建连接池管理器
    private  PoolingHttpClientConnectionManager cm;

    // 构造方法:
    public HttpUtils(){
        this.cm = new  PoolingHttpClientConnectionManager();
        // ----配置链接池.
        //1. 设置最大连接数.
        cm.setMaxTotal(100);
        // 2.设置主机分配最大连接数
        cm.setDefaultMaxPerRoute(10); // 给指定主机最大分配10个链接,为了应对多主机爬虫.
    }

    /**
     * 根据请求地址,下载页面数据
     * @param url
     * @return 页面数据
     */
    public String doGetHtml(String url){
        // 使用连接池,获取链接对象.而不是手工创建.
        CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(this.cm).build();
        HttpGet httpGet = new HttpGet(url);
        httpGet.setConfig(this.setConfig());
        // 模拟浏览器浏览（user-agent的值可以通过浏览器浏览，查看发出请求的头文件获取）
        httpGet.setHeader("user-agent", "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.113 Safari/537.36");
        CloseableHttpResponse httpResponse = null;
        try {
            // 解析响应数据.
            httpResponse = httpClient.execute(httpGet);
            if (httpResponse.getStatusLine().getStatusCode() == 200){
                String content = EntityUtils.toString(httpResponse.getEntity(),"utf8");
                return content;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            // 关闭资源.
            try {
                httpResponse.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            // 千万不能关闭httpclient.其是连接池中的对象.
            // httpClient.close();
        }
        return "";
    }



    /**
     * 下载图片.
     * @param url
     * @return 图片名称
     */
    public String doGetImage(String url){
        // 使用连接池,获取链接对象.而不是手工创建.
        CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(this.cm).build();
        HttpGet httpGet = new HttpGet(url);
        httpGet.setConfig(this.setConfig());
        CloseableHttpResponse httpResponse = null;
        try {
            // 解析响应数据.
            httpResponse = httpClient.execute(httpGet);
            if (httpResponse.getStatusLine().getStatusCode() == 200){
               // 下载图片.
                // 1.获取图片后缀
                String extName = url.substring(url.lastIndexOf("."));
                // 2.重命名
                String picName = UUID.randomUUID().toString() + extName;
                //3.下载图片
                OutputStream opt = new FileOutputStream(new File(desPath + picName));
                System.out.println("图片路径:"+desPath + picName);
                httpResponse.getEntity().writeTo(opt);
                //44.返回图片名称.
                return picName;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            // 关闭资源.
            try {
                httpResponse.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            // 千万不能关闭httpclient.其是连接池中的对象.
            // httpClient.close();
        }
        return "";
    }


    private RequestConfig setConfig() {
        // 配置请求信息
        RequestConfig config = RequestConfig.custom().setConnectTimeout(1000) //创建链接的最长是时间,单位毫秒.
                .setConnectionRequestTimeout(500) // 设置获取链接的最长时间,单位毫秒
                .setSocketTimeout(10*1000) // 设置Socket传输数据的最长时间,单位毫秒.
                .build();
        return config;
    }
}
